#pragma once
#include "CentralCache.hpp"
#include "PackageCache.hpp"
CentralCache CentralCache::_Cen;


//就是将我们的tc空间回收到cc中去
void CentralCache::ReleaselisttoSpan(void* start,size_t size)
{
    //拿到要返回的块 由于这些内存块不一定都是来自同一个span的，所以我们需要找到他们对应的span，然后插入进去
    size_t index =  SizeClass::Index(size);
    _spanlist[index]._mutex.lock();
    void* next = ObjNext(start);
    while(start)
    {
        auto it = PackageCache::create()->MaptoSpan(start);
        if(it!=nullptr)
        {
            //头插该Span中
            ObjNext(start) = it->_freelist;
            it->_freelist = start;
            //回收了tc中的一块空间
            it->_usecount--;
        }else{
            assert(false);
            return;
        }
        if(it->_usecount == 0)
        {
            //package可以回收Span了
            PackageCache::create()->_mutex.lock();
            //回收对应的span
            PackageCache::create()->ReleasePackageSpan(it);
            PackageCache::create()->_mutex.unlock();
        }
        start = next;
        next = ObjNext(next);
    }
    _spanlist[index]._mutex.unlock();
}


size_t CentralCache::FetchRangeObj(void*& start,void*& end,size_t n,size_t size)
{
    //从CC中去申请一段空间 先获取对应的哈希桶下表
    size_t index = SizeClass::Index(size);
    _spanlist[index]._mutex.lock();
    Span* span = CentralCache::create()->GetOneSpan(_spanlist[index],size);

    assert(span);
    assert(span->_freelist);

    start=end = span->_freelist;

    size_t actualNum = 1;

    while(actualNum < n-1 && ObjNext(end)!=nullptr)
    {   
        end = ObjNext(end);
        actualNum++;
    }
    span->_freelist = ObjNext(end);
    ObjNext(end) = nullptr;
    _spanlist[index]._mutex.unlock();
    span->_usecount+=actualNum;
    return actualNum;
}

Span* CentralCache::GetOneSpan(SpanList& list,size_t size)
{
    //首先需要判断的就是咱们CC中存在可以提供的Span
    Span* it = list.Begin();
    while(it != list.End())
    {
        if(it->_freelist!=nullptr)
        {
            return it;
        }else{
            it = it->_next;
        }
    }
    list._mutex.unlock();
    size_t k = SizeClass::GetPageNum(size);
    PackageCache::create()->_mutex.lock();
    //到了这里就说明CC中也没有，那就需要往PC中去申请了
    Span* span1 =  PackageCache::create()->NewSpan(k);
    span1->isUse = true;
    span1->_blocksize = size;
    PackageCache::create()->_mutex.unlock();
    //申请回来的，我们需要切割，并且加入到spanlist中去
    char* start = (char*)(span1->_pageID>>Pack_Shift);
    span1->_freelist = start; 
    char* end = (char*)(start + (span1->_n>>Pack_Shift));
    void* tail = start;
    start += size;
    //把这些切割好的块连接起来
    while(start < end)
    {
        ObjNext(tail) = start;
        tail = ObjNext(tail);
        start+=size;
    }
    list._mutex.unlock();
    list.PushFront(span1);
    ObjNext(tail)=nullptr;
    return span1;
}